import sys
import os

from importlib.machinery import SourceFileLoader

thisDir = os.path.split(os.path.realpath(__file__))[0]
sys.path.append(thisDir)

import PAIConst

import logging
logger = logging.getLogger(__name__)

class PAI:
    def __init__(self, configPath, schemaDir):
        self.__configPath = configPath
        self.__schemaDir = schemaDir
        self.__schemaPath = os.path.join(thisDir, "PAISchema.py")
        self.__constPath = os.path.join(thisDir, "PAIConst.py")
        self.__apiConfig = None
        self.__loadAPIConfig()

    def ValidateAPI(self, cmd, params):
        for aid in self.__apiConfig:
            if cmd != self.__apiConfig[aid][PAIConst.ApiName]:
                continue
            # Strict check on parameters?
            if params:
                if PAIConst.ApiParams in self.__apiConfig[aid]:
                    if len(params) != len(self.__apiConfig[aid][PAIConst.ApiParams]):
                        logger.error(f"[{aid}] Params number does not match: {params}")
                        return False
                    for param in params:
                        if len(param) != 2:
                            logger.error(f"[{aid}] Param name and value number mismatch: {param}")
                            return False
                        if not [p for p in self.__apiConfig[aid][PAIConst.ApiParams] if p[PAIConst.ApiDataValue] == param[0]]:
                            logger.error(f"[{aid}] Param name mismatch: {param}")
                            return False
                else:
                    logger.error(f"[{aid}] No param defined for {cmd}, but passed: {params}")
                    return False
            else:
                if PAIConst.ApiParams in self.__apiConfig[aid]:
                    logger.error(f"[{aid}] No param passed for {cmd}")
                    return False
            return True
        return False

    def GenerateApi(self, aid, params):
        if aid not in self.__apiConfig:
            logger.error(f"[{aid}] No match aid to generate API")
            return ""
        if PAIConst.ApiParams not in self.__apiConfig[aid] or len(self.__apiConfig[aid][PAIConst.ApiParams]) == 0:
            if len(params) != 0:
                logger.error(f"[{aid}] No params needed to generate API")
                return ""
            return self.__apiConfig[aid][PAIConst.ApiName]
        if len(self.__apiConfig[aid][PAIConst.ApiParams]) != len(params):
            logger.error(f"[{aid}] Params mismatch to generate API")
            return ""
        index = 0
        paramsLen = len(params)
        paramsResult = []
        while index < paramsLen:
            result = self.__apiConfig[aid][PAIConst.ApiParams][index][PAIConst.ApiDataValue] + "=" + params[index]
            paramsResult.append(result)
            index += 1
        return self.__apiConfig[aid][PAIConst.ApiName] + "?" + "&".join(paramsResult)

    def IsResultDefined(self, aid):
        if aid not in self.__apiConfig:
            logger.warning(f"[{aid}] No match aid to check result format")
            return False
        return PAIConst.ApiResult in self.__apiConfig[aid]

    def GetHandler(self, cmd, handlerType = PAIConst.ApiHandler):
        for aid in self.__apiConfig:
            if cmd != self.__apiConfig[aid][PAIConst.ApiName]:
                continue
            if handlerType == PAIConst.ApiHandler:
                return self.__getApiHandler(aid)
            if handlerType == PAIConst.ApiResultSuccessful:
                return self.__getResultHandler(aid, handlerType)
            logger.error(f"[{aid}] Not valid handler type: {handlerType}")
            return None
        logger.error(f"[{aid}] Not valid cmd: {cmd}")
        return None

    def __loadAPIConfig(self):
        if not os.path.isdir(self.__schemaDir):
            logger.error(f"[PAI] Invalid schema module dir: {self.__schemaDir}")
            exit(f"[PAI] Invalid schema module dir: {self.__schemaDir}")
        checkerPath = os.path.join(self.__schemaDir, "SchemaChecker.py")
        checkerModule = SourceFileLoader("SchemaChecker", checkerPath).load_module()
        checkerClass = getattr(checkerModule, "SchemaChecker")
        checker = checkerClass(self.__configPath, self.__schemaPath, self.__constPath)
        result, self.__apiConfig = checker.Check()
        if not result:
            logger.error("PAI schema check error")
            exit("PAI schema check error")

    def __getApiHandler(self, aid):
        if PAIConst.ApiHandler not in self.__apiConfig[aid]:
            logger.error(f"[{aid}] No handler defined")
            return None
        return self.__apiConfig[aid][PAIConst.ApiHandler]

    def __getResultHandler(self, aid, resultType):
        if PAIConst.ApiResult not in self.__apiConfig[aid] or len(self.__apiConfig[aid][PAIConst.ApiResult]) <= 0:
            logger.error(f"[{aid}] No result defined")
            return None
        for result in self.__apiConfig[aid][PAIConst.ApiResult]:
            if resultType in result and PAIConst.ApiHandler in result:
                return result[PAIConst.ApiHandler]
        logger.error(f"[{aid}] No result handler defined: {resultType}")
        return None
